<template>
  <div ref="readmoreContainer"
       :class="['readmore-container','multiple-line']"
       :style="{
    '-webkit-line-clamp': expandInfo.lineStyle}">
    <span class="
       display-text"
          :style="{'wordBreak':needWordBreak}">{{ expandInfo.displayText }}</span>
    <img v-if="isImage && needCollapse"
         :src="expandText"
         class="expand-text"
         @click="changeExpandStatus"
         :style="{'width': size, 'height': size}" />
    <span v-if="!isImage && needCollapse"
          class="expand-text"
          @click="changeExpandStatus"
          :style="{'--expand-text': '\'' + expandText + '\'','color':expandTextColor}"></span>
  </div>
</template>

<script>
const EXPAND_STATUS_NORMAL = "NORMAL";
const EXPAND_STATUS_MORE = "MORE";
const EXPAND_STATUS_LESS = "LESS";
const HIDE_TYPE_WORD = "WORD";
const HIDE_TYPE_CHAR = "CHAR";
const HIDE_TYPE_LINE = "LINE";

export default {
  name: "MXCompetitionTextReadmore",
  data: () => ({
    isExpand: false,
    needCollapse: null,
    collapseText: null,
    seatText: null,
    size: "16px",
    HIDE_TYPE_LINE: HIDE_TYPE_LINE,
  }),
  // text	完整文本
  // moreText	文本过长，需要展开时的提示文本
  // moreTextColor 文本颜色
  // lessText	文本过长，展开后需要隐藏时的提示文本
  // lessTextColor 文本颜色
  // hideType	隐藏规则，字符长度CHAR，单词个数WORD，行数LINE
  // maxLength	最大长度
  // isImage	是否使用图片作为提示标签
  // needWordBreak 是否需要允许在单词内换行。
  props: {
    text: {
      type: String,
      required: true,
    },
    moreText: {
      type: String,
      default: "Read More",
    },
    moreTextColor: {
      type: String,
      default: "#2C64F2",
    },
    lessText: {
      type: String,
      default: "Read Less",
    },
    lessTextColor: {
      type: String,
      default: "#2C64F2",
    },
    hideType: {
      type: String,
      default: HIDE_TYPE_LINE,
    },
    maxLength: {
      type: Number,
      default: 30,
    },
    isImage: {
      type: Boolean,
      default: false,
    },

    // normal	使用浏览器默认的换行规则。
    // break-all	允许在单词内换行。
    // keep-all	只能在半角空格或连字符处换行。
    needWordBreak: {
      type: String,
      default: "break-all",
    },
  },
  mounted() {
    this.collapseText = this.text;
    if (this.isImage) {
      this.seatText = "xx";
      this.size = window.getComputedStyle(
        this.$refs.readmoreContainer
      ).fontSize;
    } else {
      this.seatText = this.moreText;
    }
    switch (this.hideType) {
      case HIDE_TYPE_WORD:
        this.wordHandler();
        break;
      case HIDE_TYPE_CHAR:
        this.charHandler();
        break;
      case HIDE_TYPE_LINE:
        this.lineHandler((hideEle) => {
          if (hideEle.scrollHeight > hideEle.clientHeight) {
            this.checkCollapse();
          }
        });
        break;
      default:
        break;
    }
  },
  computed: {
    expandInfo() {
      let displayText = this.text;
      let status = EXPAND_STATUS_NORMAL;
      let lineStyle = "unset";
      if (this.needCollapse) {
        if (this.isExpand) {
          status = EXPAND_STATUS_MORE;
        } else {
          displayText = this.collapseText;
          status = EXPAND_STATUS_LESS;
          lineStyle = this.maxLength;
        }
      }
      return {
        status,
        displayText,
        lineStyle,
      };
    },
    expandText() {
      switch (this.expandInfo.status) {
        case EXPAND_STATUS_MORE:
          return this.lessText;
        case EXPAND_STATUS_LESS:
          return this.moreText;
        default:
          return "";
      }
    },
    expandTextColor() {
      switch (this.expandInfo.status) {
        case EXPAND_STATUS_MORE:
          return this.lessTextColor;
        case EXPAND_STATUS_LESS:
          return this.moreTextColor;
        default:
          return "";
      }
    },
  },
  methods: {
    checkCollapse() {
      this.lineHandler((hideEle, textNode) => {
        let checkCollapseText = "";
        for (let char of this.text) {
          checkCollapseText += char;
          let checkCollapseTextWithReadMore =
            checkCollapseText + "..." + this.seatText;
          textNode.textContent = checkCollapseTextWithReadMore;
          if (hideEle.scrollHeight > hideEle.clientHeight) {
            this.collapseText =
              checkCollapseText.substring(0, checkCollapseText.length - 1) +
              "...";
            this.needCollapse = true;
            break;
          }
        }
      });
    },
    changeExpandStatus() {
      this.isExpand = !this.isExpand;
    },
    wordHandler() {
      let splitArr = this.text.split(/\s+/);
      if (splitArr.length > this.maxLength) {
        let displayArry = splitArr.slice(0, this.maxLength);
        this.collapseText = displayArry.join(" ") + "... ";
        this.needCollapse = true;
      }
    },
    charHandler() {
      if (this.text.length > this.maxLength) {
        this.collapseText = this.text.substring(0, this.maxLength - 3) + "...";
        this.needCollapse = true;
      }
    },
    lineHandler(handler) {
      let hideEle = document.createElement("div");
      hideEle.style["-webkit-line-clamp"] = this.maxLength;
      hideEle.style["overflow"] = "auto";
      hideEle.style["-webkit-box-orient"] = "vertical";
      hideEle.style["display"] = "-webkit-box";
      hideEle.style["text-overflow"] = "ellipsis";
      hideEle.style["word-wrap"] = "break-word";
      let textNode = document.createTextNode(this.text);
      hideEle.appendChild(textNode);
      let currentDiv = this.$refs.readmoreContainer;
      currentDiv.appendChild(hideEle);
      handler(hideEle, textNode);
      currentDiv.removeChild(hideEle);
    },
  },
};
</script>

<style scoped>
.display-text {
  word-wrap: break-word;
}
.expand-text {
  float: right;
}

.expand-text::before {
  content: var(--expand-text);
}

.multiple-line {
  -webkit-box-orient: vertical;
  display: -webkit-box;
  overflow: hidden;
  text-overflow: ellipsis;
}
</style>